package cn.xiaolang.thread.juc;

import cn.xiaolang.common.utils.Monitor;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * compare with AtomicInteger int volatile
 *
 * @author Dean
 * @date 2021-08-17
 */
public class AtomicCompareSample {

    // 最大等待时长
    private static final int MAX_AWAIT_TIME = 10;

    private static final AtomicInteger atomicInteger = new AtomicInteger(0);
    private static int intValue = 0;
    private static volatile int volatileCount = 0;
    private static int intValueSync = 0;


    /**
     * <h3>AtomicInteger</h3>
     * 并发量够高的情况,但是需要注意的是AtomicInteger类只能保证在自增或者自减的情况下保证线程安全
     * 并发量不高的情况下，区别不明显
     * 原子操作：当前变量只允许一个线程来操作，不接受多线程来访问。所以每次的都是最新的值
     *
     * <h3>volatile</h3>
     * 当一个变量定义为 volatile 之后，将具备两种特性：
     * <p>
     * 1.保证此变量对所有的线程的可见性，但不能保证原子行,这里的“可见性”，示例: A线程对t变量修改的值，对B线程是可见的。但是A获取到t的值加1之后，突然挂起了，
     * B线程可能会在这个操作还没有完成时读到变量的旧值，因为A的t+1并没有写到主内存里面去，然后进行一些操作，这样就会导致数据的不一致性。
     * <p>
     * 如本文开头所述，当一个线程修改了这个变量的值，volatile
     * 保证了新值能立即同步到主内存，以及每次使用前立即从主内存刷新。但普通变量做不到这点，普通变量的值在线程间传递均需要通过主内存（详见：Java内存模型）来完成。
     * <p>
     * <p>
     * 2.禁止指令重排序优化。有volatile修饰的变量，赋值后多执行了一个“load addl $0x0,(%esp)”操作，
     * 这个操作相当于一个内存屏障（指令重排序时不能把后面的指令重排序到内存屏障之前的位置），
     * 只有一个CPU访问内存时，并不需要内存屏障；（什么是指令重排序：是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理）。
     * <p>
     * volatile 性能：
     * volatile的读性能消耗与普通变量几乎相同，但是写操作稍慢，因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行
     * 在访问volatile变量时不会执行加锁操作，因此也就不会使执行线程阻塞，因此volatile变量是一种比sychronized关键字更轻量级的同步机制。
     *
     * <h3>示例结果：</h3>
     * <pre>
     * int++结果是: 49892 所用时间：0.179(秒)
     * int++ with synchronized 结果是: 50000 所用时间：0.034(秒)
     * atomic自增结果是: 50000 所用时间：0.022(秒)
     * volatile修饰int自增结果是: 49983 所用时间：0.029(秒)
     * </pre>
     */
    public static void main(String[] args) throws InterruptedException {
        int numThreads = 10;
        int workCount = 100000;

        Monitor.begin();
        doIncreaseWork(numThreads, workCount, () -> intValue++);
        Monitor.end("int++结果是: " + intValue);
        Thread.sleep(2000);

        Monitor.begin();
        doIncreaseWork(numThreads, workCount, AtomicCompareSample::increaseSync);
        Monitor.end("int++ with synchronized 结果是: " + intValueSync);
        Thread.sleep(2000);

        Monitor.begin();
        doIncreaseWork(numThreads, workCount, atomicInteger::incrementAndGet);
        Monitor.end("atomic自增结果是: " + atomicInteger.get());
        Thread.sleep(2000);

        Monitor.begin();
        doIncreaseWork(numThreads, workCount, () -> volatileCount++);
        Monitor.end("volatile修饰int自增结果是: " + volatileCount);

    }

    private static void doIncreaseWork(int numThreads, int workCount, Runnable incrWorker) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(numThreads);
        for (int i = 0; i < workCount; i++) {
            executorService.execute(incrWorker);
        }
        executorService.shutdown();
        executorService.awaitTermination(MAX_AWAIT_TIME, TimeUnit.SECONDS);
    }

    private static synchronized void increaseSync() {
        intValueSync++;
    }


}
